package avicit.bdp.dds.api.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.DateUtils;
import avicit.bdp.dds.dispatch.enums.DependResult;
import avicit.bdp.dds.dispatch.enums.ExecutionStatus;
import avicit.bdp.dds.dispatch.enums.TaskType;
import avicit.bdp.dds.dispatch.model.TaskNode;
import avicit.bdp.core.util.json.JSONUtils;
import avicit.bdp.dds.api.utils.TaskStateUtils;
import avicit.bdp.dds.common.Constants;
import avicit.bdp.dds.dao.entity.ProcessInstance;
import avicit.bdp.dds.dao.entity.TaskInstance;
import avicit.bdp.dds.dao.mapper.ProcessInstanceMapper;
import avicit.bdp.dds.dao.mapper.TaskInstanceMapper;
import avicit.bdp.dds.service.process.ProcessService;
import avicit.platform6.core.rest.msg.QueryRespBean;
import avicit.platform6.core.rest.msg.ResponseMsg;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author admin
 */
@Service
public class TaskInstanceService extends BaseService<TaskInstanceMapper, TaskInstance> {

    private static final Logger logger = LoggerFactory.getLogger(TaskInstanceService.class);
    @Autowired
    private ProcessInstanceMapper processInstanceMapper;
    @Autowired
    private LoggerService loggerService;
    @Autowired
    private ProcessService processService;


    public List<TaskInstance> getTaskProcess(String id, String processDefinitionId) {
        if (StringUtils.isBlank(id)) {
            ProcessInstance instance = processInstanceMapper.queryLastOneProcess(processDefinitionId);
            if (instance != null) {
                id = instance.getId();
            } else {
                return new ArrayList<>();
            }
        }
        TaskInstance taskInstanceQuery = new TaskInstance();
        taskInstanceQuery.setProcessInstanceId(id);
        List<TaskInstance> list = this.selectList(taskInstanceQuery);
        for (TaskInstance task : list) {
            TaskNode node = JSONUtils.parseObject(task.getTaskJson(), TaskNode.class);
            if (node != null && StringUtils.isNotBlank(node.getOriginalName())) {
                task.setTaskTypeName(node.getOriginalName());
            } else {
                task.setTaskTypeName(task.getTaskType());
            }

        }
        return list;
    }

    /**
     * @param processInstanceId processInstanceId
     * @param node              node
     * @return 节点信息
     */
    public TaskInstance queryByInstanceIdAndName(String processInstanceId, String node) {
        return this.mapper.queryByInstanceIdAndName(processInstanceId, node);
    }

    /**
     * 查询所有节点数
     *
     * @param processDefinitionId processDefinitionId
     * @param processInstanceId   processInstanceId
     * @return 节点信息
     */
    public Long selectAllNoteCount(String processDefinitionId, String processInstanceId) {
        return this.mapper.selectAllNoteCount(processDefinitionId, processInstanceId);
    }

    /**
     * 查询成功运行完的节点
     *
     * @param processDefinitionId processDefinitionId
     * @param processInstanceId   processInstanceId
     * @return 节点信息
     */
    public Long selectSuccessCount(String processDefinitionId, String processInstanceId) {
        return this.mapper.selectSuccessCount(processDefinitionId, processInstanceId);
    }

    /**
     * 查询运行中的节点信息
     *
     * @param processDefinitionId processDefinitionId
     * @param processInstanceId   processInstanceId
     * @return 节点信息
     */
    public List<TaskInstance> selectListByInstanceId(String processDefinitionId, String processInstanceId, Integer state, Integer nodeType) {
        return this.mapper.selectListByInstanceId(processDefinitionId, processInstanceId, state, nodeType);
    }


    /**
     * 查询各种状态的节点统计
     *
     * @param today         today
     * @param projectIdList projectIdList
     * @param state         state
     * @return DataCount
     */
    public Long getDataCount(String today, List<String> projectIdList, Integer state) {
        return this.mapper.getDataCount(today, projectIdList, state);
    }

    /**
     * 运行慢节点统计
     *
     * @param today         today
     * @param projectIdList projectIdList
     * @param state         state
     * @param slowTime      slowTime
     * @return SlowCount
     */
    public Long getSlowCount(String today, List<String> projectIdList, Integer state, Long slowTime) {
        return this.mapper.getSlowCount(today, projectIdList, state, slowTime);
    }

    /**
     * @param today     today
     * @param projectId projectId
     * @param state     state
     * @return DataCount
     */
    public Long getDataCountByProjectId(String today, String projectId, Integer state) {
        return this.mapper.getDataCountByProjectId(today, projectId, state);
    }

    /**
     * @param today     today
     * @param projectId projectId
     * @param state     state
     * @param slowTime  slowTime
     * @return SlowCount
     */
    public Long getSlowCountByProjectId(String today, String projectId, Integer state, Long slowTime) {
        return this.mapper.getSlowCountByProjectId(today, projectId, state, slowTime);
    }

    public Map<String, Object> getFlowTaskProcess(String id, String processDefinitionId) {
        Map<String, Object> result = new HashMap<>();
        ProcessInstance instance = null;
        if (StringUtils.isBlank(id)) {
            instance = processInstanceMapper.queryLastOneProcess(processDefinitionId);
        } else {
            instance = processInstanceMapper.getInstanceStateById(id);
        }
        if (instance == null) {
            result.put("id", id);
            result.put("state", 0);
            return result;
        }
        result.put("id", instance.getId());
        result.put("state", TaskStateUtils.convertTaskState(instance.getState()));

        List<Map<String, Object>> resultList = new ArrayList<>();
        List<TaskInstance> list = this.mapper.getFlowTaskProcessByInstanceId(instance.getId());
        Map<String, Object> map = null;
        for (TaskInstance task : list) {
            map = new HashMap<>();
            map.put("id", task.getId());
            map.put("name", task.getName());
            int state = TaskStateUtils.convertTaskState(task.getState());
            String stateName = TaskStateUtils.convertStateName(state);
            map.put("state", state);
            map.put("stateName", stateName);
            String startTime = task.getStartTime() == null ? "" : DateUtils.format(task.getStartTime());
            String endTime = task.getEndTime() == null ? "" : DateUtils.format(task.getEndTime());
            map.put("startTime", startTime);
            map.put("endTime", endTime);
            map.put("chartType", task.getChartType() == null ? 0 : task.getChartType());
            map.put("nodeType", task.getNodeType() == null ? 0 : task.getNodeType());
            resultList.add(map);

        }
        logger.debug("task num: " + resultList.size());
        result.put("nodesList", resultList);
        return result;
    }

    /**
     * query task list by process instance id
     *
     * @param processId process instance id
     * @return task list for the process instance
     * @throws IOException io exception
     */
    public List<TaskInstance> queryTaskListByProcessId(String processId) throws IOException {
        List<TaskInstance> taskInstanceList = processService.findValidTaskListByProcessId(processId);
        addDependResultForTaskList(taskInstanceList);
        return taskInstanceList;
    }

    /**
     * add dependent result for dependent task
     *
     * @param taskInstanceList taskInstanceList
     */
    private void addDependResultForTaskList(List<TaskInstance> taskInstanceList) throws IOException {
        for (TaskInstance taskInstance : taskInstanceList) {
            if (taskInstance.getTaskType().equalsIgnoreCase(TaskType.DEPENDENT.toString())) {
                ResponseMsg<String> logResult = loggerService.queryLog(taskInstance.getId(), 0, 4098);
                if ("200".equals(logResult.getRetCode())) {
                    String log = logResult.getResponseBody();
                    Map<String, DependResult> resultMap = parseLogForDependentResult(log);
                    taskInstance.setDependentResult(JSONUtils.toJson(resultMap));
                }
            }
        }
    }

    private Map<String, DependResult> parseLogForDependentResult(String log) throws IOException {
        Map<String, DependResult> resultMap = new HashMap<>(16);
        if (org.apache.commons.lang3.StringUtils.isEmpty(log)) {
            return resultMap;
        }

        BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(log.getBytes(
                StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
        String line;
        while ((line = br.readLine()) != null) {
            if (line.contains(Constants.DEPENDENT_SPLIT)) {
                String[] tmpStringArray = line.split(":\\|\\|");
                if (tmpStringArray.length != 2) {
                    continue;
                }
                String dependResultString = tmpStringArray[1];
                String[] dependStringArray = dependResultString.split(Constants.COMMA);
                if (dependStringArray.length != 2) {
                    continue;
                }
                String key = dependStringArray[0].trim();
                DependResult dependResult = DependResult.valueOf(dependStringArray[1].trim());
                resultMap.put(key, dependResult);
            }
        }
        return resultMap;
    }

    public List<Map<String, Object>> getFlowTaskStateCount(List<String> runningIdList) {
        return this.mapper.getFlowTaskStateCount(runningIdList);
    }
}
